package com.ayla.demo.widgets.adapter

import android.annotation.SuppressLint
import android.view.ViewGroup
import androidx.recyclerview.widget.*
import androidx.recyclerview.widget.AsyncListDiffer.ListListener
import androidx.viewbinding.ViewBinding
import com.ayla.demo.widgets.binder.AbsItemBinder
import com.ayla.demo.widgets.touch.ITouch
import java.util.*
import kotlin.collections.HashMap

class BinderAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>(), ITouch {

    private val list = mutableListOf<Any>()

    private val diffUtilMap = HashMap<Class<*>, DiffUtil.ItemCallback<Any>>()
    private val typeMap = HashMap<Class<*>, Int>()
    private val binderMap = HashMap<Int, AbsItemBinder<Any, *>>()

    private val asyncListDiffer = AsyncListDiffer(
        AdapterListUpdateCallback(this),
        AsyncDifferConfig.Builder(ListBinderItemCallback()).build()
    )

    fun submitList(list: List<Any>?, callback: Runnable? = null) {
//        asyncListDiffer.submitList(list, callback)
        this.list.clear()
        if (list.isNullOrEmpty()) {
            notifyDataSetChanged()
            return
        }
        this.list.addAll(list)
        notifyDataSetChanged()
    }

    fun getItem(position: Int): Any {
//        return asyncListDiffer.currentList[position]
        return list[position]
    }

    override fun getItemCount(): Int = list.size

    fun getCurrentList(): List<Any> = asyncListDiffer.currentList

    fun <T : Any> addItemBinder(
        clazz: Class<T>,
        binder: AbsItemBinder<T, *>,
        callback: DiffUtil.ItemCallback<Any>? = null
    ) {
        val itemType = typeMap.size + 1
        typeMap[clazz] = itemType
        binderMap[itemType] = binder as AbsItemBinder<Any, *>
        binder._adapter = this
        callback?.let {
            diffUtilMap[clazz] = it
        }
    }

    inline fun <reified T : Any> addItemBinder(
        binder: AbsItemBinder<T, *>,
        callback: DiffUtil.ItemCallback<Any>? = null
    ) {
        addItemBinder(T::class.java, binder, callback)
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        val binder = findBinderByViewType(viewType)
        binder._context = parent.context
        val holder = binder.onCreateViewHolder(parent, viewType)
        binder.onViewHolderCreated(holder, viewType)
        return holder
    }

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        val data = getItem(position)
        val binder = findBinderByViewType(holder.itemViewType)
        binder.convert(holder, data)
    }

    override fun onBindViewHolder(
        holder: RecyclerView.ViewHolder,
        position: Int,
        payloads: MutableList<Any>
    ) {
        if (payloads.isEmpty()) {
            super.onBindViewHolder(holder, position, payloads)
            return
        }
        val data = getItem(position)
        val binder = findBinderByViewType(holder.itemViewType)
        binder.convert(holder, data, payloads)
    }

    override fun getItemViewType(position: Int): Int {
        val clazz = getItem(position).javaClass
        val type = typeMap[clazz]
        checkNotNull(type) {
            "没有发现 clazz = $clazz 对应的type, 需要先调用addItemBinder"
        }
        return type
    }

    override fun getItemId(position: Int): Long {
        return position.toLong()
    }

    override fun onViewAttachedToWindow(holder: RecyclerView.ViewHolder) {
        super.onViewAttachedToWindow(holder)
        findBinderByViewType(holder.itemViewType).onViewAttachedToWindow(holder)
    }

    override fun onViewDetachedFromWindow(holder: RecyclerView.ViewHolder) {
        super.onViewDetachedFromWindow(holder)
        findBinderByViewType(holder.itemViewType).onViewDetachedFromWindow(holder)
    }

    private fun findBinderByViewType(viewType: Int): AbsItemBinder<Any, out ViewBinding> {
        val binder = binderMap[viewType]
        checkNotNull(binder) {
            "没有找到 viewType = $viewType 对应的Binder, 需要先调用addItemBinder"
        }
        return binder
    }

    fun addListListener(listener: ListListener<Any>) {
        asyncListDiffer.addListListener(listener)
    }

    fun removeListListener(listener: ListListener<Any>) {
        asyncListDiffer.removeListListener(listener)
    }

    private inner class ListBinderItemCallback() : DiffUtil.ItemCallback<Any>() {
        override fun areItemsTheSame(oldItem: Any, newItem: Any): Boolean {
            if (oldItem.javaClass == newItem.javaClass) {
                val callback = diffUtilMap[newItem.javaClass]
                if (callback != null) {
                    return callback.areItemsTheSame(oldItem, newItem)
                }
            }
            return oldItem == newItem
        }

        @SuppressLint("DiffUtilEquals")
        override fun areContentsTheSame(oldItem: Any, newItem: Any): Boolean {
            if (oldItem.javaClass == newItem.javaClass) {
                val callback = diffUtilMap[newItem.javaClass]
                if (callback != null) {
                    return callback.areContentsTheSame(oldItem, newItem)
                }
            }
            return false
        }

        override fun getChangePayload(oldItem: Any, newItem: Any): Any? {
            if (oldItem.javaClass == newItem.javaClass) {
                val callback = diffUtilMap[newItem.javaClass]
                if (callback != null) {
                    return callback.getChangePayload(oldItem, newItem)
                }
            }
            return super.getChangePayload(oldItem, newItem)
        }
    }

    override fun onDrag(viewHolder: RecyclerView.ViewHolder, actionState: Int) {
        val binder = findBinderByViewType(viewHolder.itemViewType)
        binder.onDrag(viewHolder)
    }

//    private val list = LinkedList<Any>()

    private fun inRange(position: Int): Boolean {
        return position >= 0 && position < list.size
    }

    override fun onMove(
        source: RecyclerView.ViewHolder,
        sourcePosition: Int,
        target: RecyclerView.ViewHolder,
        targetPosition: Int
    ): Boolean {
        if (sourcePosition == targetPosition) {
            return true
        }
//        val list = LinkedList(getCurrentList())
//        if (targetPosition < sourcePosition) {
//            val sourceData = list.removeAt(sourcePosition)
//            list.add(targetPosition, sourceData)
//        } else {
//            val sourceData = list.removeAt(sourcePosition)
//            list.add(targetPosition - 1, sourceData)
//        }
//        submitList(list)

        if (inRange(sourcePosition) && inRange(targetPosition)) {
            if (sourcePosition < targetPosition) {
                for (i in sourcePosition until targetPosition) {
                    Collections.swap(list, i, i + 1)
                }
            } else {
                for (i in sourcePosition downTo targetPosition + 1) {
                    Collections.swap(list, i, i - 1)
                }
            }
            notifyItemMoved(sourcePosition, targetPosition)
        }
        return true
    }

    override fun onSwipe(viewHolder: RecyclerView.ViewHolder, actionState: Int) {

    }

    override fun onEnd(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) {
        val binder = findBinderByViewType(viewHolder.itemViewType)
        binder.onDrag(viewHolder)
    }
}

